#include <GameEngine/Graphics/Texture/texture_coordinates.h>

#include <GameEngine/Graphics/openGL.h>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif


//! Default constructor
/*!
 @param index The index of the texture (0 if one single texture is used)
 */
TextureCoordinateMulti::TextureCoordinateMulti(Texture::TextureIndex index) : index_(index) {}

//! Constructor for 1D texture coordinates
/*!
 @param u The first coordinate of the texture
 @param index The index of the texture (0 if one single texture is used)
 */
TextureCoordinateMulti::TextureCoordinateMulti(float u, Texture::TextureIndex index) : index_(index), coordinates_(1) {
	coordinates_.push_back(u);
}

//! Constructor for 2D texture coordinates
/*!
 @param u The first coordinate of the texture
 @param v The second coordinate of the texture
 @param index The index of the texture (0 if one single texture is used)
 */
TextureCoordinateMulti::TextureCoordinateMulti(float u, float v, Texture::TextureIndex index) : index_(index), coordinates_(2) {
	coordinates_.push_back(u);
	coordinates_.push_back(v);
}

//! Constructor for 3D texture coordinates
/*!
 @param u The first coordinate of the texture
 @param v The second coordinate of the texture
 @param w The third coordinate of the texture
 @param index The index of the texture (0 if one single texture is used)
 */
TextureCoordinateMulti::TextureCoordinateMulti(float u, float v, float w, Texture::TextureIndex index) : index_(index), coordinates_(3) {
	coordinates_.push_back(u);
	coordinates_.push_back(v);
	coordinates_.push_back(w);
}

//! Copy constructor
/*!
 @param rhs The texture coordinate to copy
 */
TextureCoordinateMulti::TextureCoordinateMulti(const TextureCoordinateMulti& rhs) : index_(rhs.index_), coordinates_(rhs.coordinates_) {}

//! Assignment operator
/*!
 @param rhs The texture coordinate to copy
 @return A reference to this transformed texture coordinate
 */
TextureCoordinateMulti& TextureCoordinateMulti::operator=(const TextureCoordinateMulti& rhs) {
	if ( &rhs != this ) {
		index_ = rhs.index_;
		coordinates_ = rhs.coordinates_;
	}
	return *this;
}

//! Destructor
TextureCoordinateMulti::~TextureCoordinateMulti() {}

//! Apply the texture coordinates
void TextureCoordinateMulti::apply_coordinates() const {
	// Check coordinates size
	int size = (int)coordinates_.size();
	if ( size == 0 ) return;

	// Apply the texture
	if ( size == 1 ) glMultiTexCoord1f(GL_TEXTURE0+index_,coordinates_[0]);
	else if ( size == 2 ) glMultiTexCoord2f(GL_TEXTURE0+index_,coordinates_[0],coordinates_[1]);
	else glMultiTexCoord3f(GL_TEXTURE0+index_,coordinates_[0],coordinates_[1],coordinates_[2]);
}


//==============================================================================


//! Default constructor
/*!
 @note Texture coordinates are defaulted to 0
 */
TextureCoordinate1d::TextureCoordinate1d() : u_(0.0f) {}

//! Constructor
/*!
 @param u The texture coordinate
 */
TextureCoordinate1d::TextureCoordinate1d(float u) : u_(u) {}

//! Copy constructor
/*!
 @param rhs The texture coordinate to copy
 */
TextureCoordinate1d::TextureCoordinate1d(const TextureCoordinate1d& rhs) : u_(rhs.u_) {}

//! Assignment operator
/*!
 @param rhs The texture coordinate to copy
 @return A reference to this texture coordinate
 */
TextureCoordinate1d& TextureCoordinate1d::operator=(const TextureCoordinate1d& rhs) {
	if ( &rhs != this ) {
		u_ = rhs.u_;
	}
	return *this;
}

//! Destructor
TextureCoordinate1d::~TextureCoordinate1d() {}

//! Apply the texture coordinates
/*!
 @param texture_index The index of the texture to which texture coordinates do apply. This index
                      should be different than 0 for multitexturing
 */
void TextureCoordinate1d::apply_coordinates(Texture::TextureIndex texture_index) const {
	glMultiTexCoord1f(GL_TEXTURE0+texture_index,u_);
}

//! Accessor to the texture coordinate (read only)
/*!
 @return The texture coordinate
 */
float TextureCoordinate1d::u() const {
	return u_;
}

//! Accessor to the texture coordinate (read-write)
/*!
 @return A reference to the texture coordinate
 */
float& TextureCoordinate1d::u() {
	return u_;
}


//==============================================================================


//! Default constructor
/*!
 @note Texture coordinates are defaulted to 0
 */
TextureCoordinate2d::TextureCoordinate2d() : u_(0.0f), v_(0.0f) {}

//! Constructor
/*!
 @param u The first texture coordinate
 @param v The second texture coordinate
 */
TextureCoordinate2d::TextureCoordinate2d(float u, float v) : u_(u), v_(v) {}

//! Copy constructor
/*!
 @param rhs The texture coordinate to copy
 */
TextureCoordinate2d::TextureCoordinate2d(const TextureCoordinate2d& rhs) : u_(rhs.u_), v_(rhs.v_) {}

//! Assignment operator
/*!
 @param rhs The texture coordinate to copy
 @return A reference to this texture coordinate
 */
TextureCoordinate2d& TextureCoordinate2d::operator=(const TextureCoordinate2d& rhs) {
	if ( &rhs != this ) {
		u_ = rhs.u_;
		v_ = rhs.v_;
	}
	return *this;
}

//! Destructor
TextureCoordinate2d::~TextureCoordinate2d() {}

//! Apply the texture coordinates
/*!
 @param texture_index The index of the texture to which texture coordinates do apply. This index
                      should be different than 0 for multitexturing
 */
void TextureCoordinate2d::apply_coordinates(Texture::TextureIndex texture_index) const {
	glMultiTexCoord2f(GL_TEXTURE0+texture_index,u_,v_);
}

//! Accessor to the first texture coordinate (read only)
/*!
 @return The first texture coordinate
 */
float TextureCoordinate2d::u() const {
	return u_;
}

//! Accessor to the first texture coordinate (read-write)
/*!
 @return A reference to the first texture coordinate
 */
float& TextureCoordinate2d::u() {
	return u_;
}

//! Accessor to the second texture coordinate (read only)
/*!
 @return The second texture coordinate
 */
float TextureCoordinate2d::v() const {
	return v_;
}

//! Accessor to the second texture coordinate (read-write)
/*!
 @return A reference to the second texture coordinate
 */
float& TextureCoordinate2d::v() {
	return v_;
}


//==============================================================================


//! Default constructor
/*!
 @note Texture coordinates are defaulted to 0
 */
TextureCoordinate3d::TextureCoordinate3d() : u_(0.0f), v_(0.0f), w_(0.0f) {}

//! Constructor
/*!
 @param u The first texture coordinate
 @param v The second texture coordinate
 @param w The third texture coordinate
 */
TextureCoordinate3d::TextureCoordinate3d(float u, float v, float w) : u_(u), v_(v), w_(w) {}

//! Copy constructor
/*!
 @param rhs The texture coordinate to copy
 */
TextureCoordinate3d::TextureCoordinate3d(const TextureCoordinate3d& rhs) : u_(rhs.u_), v_(rhs.v_), w_(rhs.w_) {}

//! Assignment operator
/*!
 @param rhs The texture coordinate to copy
 @return A reference to this texture coordinate
 */
TextureCoordinate3d& TextureCoordinate3d::operator=(const TextureCoordinate3d& rhs) {
	if ( &rhs != this ) {
		u_ = rhs.u_;
		v_ = rhs.v_;
		w_ = rhs.w_;
	}
	return *this;
}

//! Destructor
TextureCoordinate3d::~TextureCoordinate3d() {}

//! Apply the texture coordinates
/*!
 @param texture_index The index of the texture to which texture coordinates do apply. This index
                      should be different than 0 for multitexturing
 */
void TextureCoordinate3d::apply_coordinates(Texture::TextureIndex texture_index) const {
	glMultiTexCoord3f(GL_TEXTURE0+texture_index,u_,v_,w_);
}

//! Accessor to the first texture coordinate (read only)
/*!
 @return The first texture coordinate
 */
float TextureCoordinate3d::u() const {
	return u_;
}

//! Accessor to the first texture coordinate (read-write)
/*!
 @return A reference to the first texture coordinate
 */
float& TextureCoordinate3d::u() {
	return u_;
}

//! Accessor to the second texture coordinate (read only)
/*!
 @return The second texture coordinate
 */
float TextureCoordinate3d::v() const {
	return v_;
}

//! Accessor to the second texture coordinate (read-write)
/*!
 @return A reference to the second texture coordinate
 */
float& TextureCoordinate3d::v() {
	return v_;
}

//! Accessor to the third texture coordinate (read only)
/*!
 @return The second third coordinate
 */
float TextureCoordinate3d::w() const {
	return w_;
}

//! Accessor to the third texture coordinate (read-write)
/*!
 @return A reference to the third texture coordinate
 */
float& TextureCoordinate3d::w() {
	return w_;
}



#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif
